package com.nsi.service.Impl;


import com.google.gson.Gson;
import com.nsi.async.AsyncTask;
import com.nsi.common.Const;
import com.nsi.common.ServerResponse;
import com.nsi.dao.OrderMapper;
import com.nsi.exception.NsiOperationException;
import com.nsi.pojo.Log;
import com.nsi.pojo.Order;
import com.nsi.service.IOrderService;
import com.nsi.service.IWxPayService;
import com.nsi.util.*;
import com.wechat.pay.*;
import com.wechat.share.WxchatShareUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;


/**
 * @author Luo Zhen
 * @create 2018-08-07
 */
@Slf4j
@Service
public class WxPayServiceImpl implements IWxPayService {


    /**
     * 四库全书 小程序(appid/secret)
     */
    private static final String WXSP_COMM_APPID = "wxdd4062215242e2d2";
    private static final String WXSP_COMM_SECRET = "dc05daa754d8ca27eac7c1d3386f5494";

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private AsyncTask asyncTask;
    @Autowired
    private IOrderService iOrderService;


    @Override
    public ServerResponse getUserByCodeAndIv(String type, String code, String encryptedData, String iv) {
        String params = null;
        if ("1".equals(type)) {
            //拼参 四库全书
            params = "appid=" + PropertiesUtil.getProperty("miniProgram.siku.appid") + "&secret=" + PropertiesUtil.getProperty("miniProgram.siku.appSecret") + "&js_code=" + code + "&grant_type="
                    + PropertiesUtil.getProperty("miniProgram.common.type");
        }

        if ("2".equals(type)) {
            //拼参 教育社区
            params = "appid=" + PropertiesUtil.getProperty("miniProgram.pitaya.appid") + "&secret=" + PropertiesUtil.getProperty("miniProgram.pitaya.appSecret") + "&js_code=" + code + "&grant_type="
                    + PropertiesUtil.getProperty("miniProgram.common.type");
        }

        String sr = HttpRequest.sendGet("https://api.weixin.qq.com/sns/jscode2session", params);
        //解析内容
        JSONObject json = new JSONObject(sr);
        String session_key = (String) json.get("session_key");
        if (StringUtils.isBlank(session_key)) {
            log.error("【微信小程序获取信息失败】:{}", json.toString());
            throw new NsiOperationException("微信小程序获取sessionKey异常!");
        }
        //对encryptedData 加密数据进行AES解密
        Map map = new HashMap();
        try {
            String result = AesCbcUtil.decrypt(encryptedData, session_key, iv, "UTF-8");
            if (null != result && result.length() > 0) {
                JSONObject userInfoJSON = new JSONObject(result);
                map.put("openId", userInfoJSON.get("openId"));
                map.put("nickName", userInfoJSON.get("nickName"));
                map.put("gender", userInfoJSON.get("gender"));
                map.put("city", userInfoJSON.get("city"));
                map.put("province", userInfoJSON.get("province"));
                map.put("country", userInfoJSON.get("country"));
                map.put("avatarUrl", userInfoJSON.get("avatarUrl"));
                map.put("unionId", userInfoJSON.get("unionId"));
            } else {
                return ServerResponse.createByErrorMessage("解密失败");
            }
        } catch (Exception e) {
            log.error("-------------------> 解密异常");
            e.printStackTrace();
        }
        return ServerResponse.createBySuccess(map);

    }

    /**
     * 根据授权请求获取openid
     *
     * @param code
     * @return
     */
    @Override
    public ServerResponse getOpenId(String code) {
        if (StringUtils.isBlank(code)) {
            return ServerResponse.createByErrorMessage("code为空，参数不合法");
        }
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        url = url.replaceAll("APPID", WxPayConfig.appid).replaceAll("CODE", code).replaceAll("SECRET", WxPayConfig.secret);
        String respJson = null;
        try {
            respJson = Httpsrequest.httpsRequest(url, "GET", null);
            log.info("【微信授权获取用户信息】respJson:{}" + respJson);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (respJson == null) {
            return ServerResponse.createByErrorMessage("json数据有误");
        }
        //将json数据还原成对象
        Gson gson = new Gson();
        Token token = gson.fromJson(respJson, Token.class);
        if (token == null) {
            return ServerResponse.createByErrorMessage("返回参数有误");
        }
        return ServerResponse.createBySuccess(token);
    }

    /**
     * 根据授权请求获取微信用户信息
     *
     * @param code
     * @return
     */
    @Override
    public ServerResponse getUserInfo(String code) {
        ServerResponse response = this.getOpenId(code);
        if (!response.isSuccess()) {
            return response;
        }
        //取参数
        Token token = (Token) response.getData();
        if (token == null) {
            return ServerResponse.createByErrorMessage("Token无效，无法继续操作");
        }
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
        url = url.replaceAll("ACCESS_TOKEN", token.getAccess_token()).replaceAll("OPENID", token.getOpenid());
        String respJson = null;
        try {
            respJson = Httpsrequest.httpsRequest(url, "GET", null);
            log.info("【微信授权获取用户信息】respJson:{}" + respJson);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (respJson == null) {
            return ServerResponse.createByErrorMessage("json数据有误");
        }
        Gson gson = new Gson();
        WxUser wxUser = gson.fromJson(respJson, WxUser.class);
        if (wxUser == null) {
            return ServerResponse.createByErrorMessage("返回参数有误");
        }
        return ServerResponse.createBySuccess(wxUser);
    }


    /**
     * 微信公众号支付
     *
     * @param openid
     * @return
     */

    @Override
    public ServerResponse wxPayment(String openid, String body, String total_fee, String attach) {
        if (StringUtils.isBlank(openid)) {
            return ServerResponse.createByErrorMessage("openid不能为空");
        }
        if (StringUtils.isBlank(body) || StringUtils.isBlank(attach)) {
            return ServerResponse.createByErrorMessage("參數不合法");
        }
        if (total_fee == null) {
            return ServerResponse.createByErrorMessage("价格参数不为空");
        }
        //扫码支付
        SortedMap map = WxPaymentUtil.pay(openid, body, total_fee, attach);
        return ServerResponse.createBySuccess(map);
    }

    /**
     * 微信公众号支付
     *
     * @param body
     * @param total_fee
     * @param attach
     * @param spbillIp
     * @param sceneInfo
     * @return
     */
    @Override
    public ServerResponse wxPaymentH5(String body, String total_fee, String attach, String spbillIp, String sceneInfo) {
        if (StringUtils.isBlank(spbillIp)) {
            return ServerResponse.createByErrorMessage("终端IP不能为空");
        }
        if (StringUtils.isBlank(body) || StringUtils.isBlank(attach)) {
            return ServerResponse.createByErrorMessage("參數不合法");
        }
        if (StringUtils.isBlank(total_fee)) {
            return ServerResponse.createByErrorMessage("价格参数不为空");
        }
        if (StringUtils.isBlank(sceneInfo)) {
            return ServerResponse.createByErrorMessage("场景信息参数不为空");
        }
        String webUrl = WxPaymentUtil.payH5(body, total_fee, attach, spbillIp, sceneInfo);
        if (StringUtils.isNotBlank(webUrl)) {
            return ServerResponse.createBySuccess("返回支付地址", webUrl);
        }
        return ServerResponse.createByError();
    }

    /**
     * 微信分享
     *
     * @param url
     * @return
     */
    @Override
    public ServerResponse wxChatShare(String url) {
        if (StringUtils.isBlank(url)) {
            return ServerResponse.createByErrorMessage("参数不合法");
        }
        HashMap<String, String> resultMap = WxchatShareUtil.wxChatSign(url);
        return ServerResponse.createBySuccess(resultMap);
    }

    /**
     * 微信原生扫码支付
     *
     * @param body
     * @param total_fee
     * @param attach
     * @return
     */
    @Override
    public ServerResponse wxPaymentQrCode(String body, String total_fee, String attach, String out_trade_no) {
        if (StringUtils.isBlank(body) || StringUtils.isBlank(attach) || StringUtils.isBlank(out_trade_no)) {
            return ServerResponse.createByErrorMessage("参数不合法");
        }
        if (StringUtils.isBlank(total_fee)) {
            return ServerResponse.createByErrorMessage("价格参数不为空");
        }
        String codeUrl = WxPaymentUtil.payQrCode(body, total_fee, attach, out_trade_no);
        return ServerResponse.createBySuccess(codeUrl);
    }

    /**
     * 微信轮询接口
     *
     * @param orderNo
     * @return
     */
    @Override
    public ServerResponse queryOrderPayStatus(String orderNo) {
        if (StringUtils.isBlank(orderNo)) {
            return ServerResponse.createByErrorMessage("参数不合法");
        }
        Order order = orderMapper.findOrderByOrderNoAndType(orderNo);

        if (null == order) {
            return ServerResponse.createByError("未支付或没有订单");
        }
        return ServerResponse.createBySuccess();
    }

    /**
     * 插入log信息
     *
     * @param info
     * @param transaction_id
     * @param out_trade_no
     * @return
     */
    private Log insertPayInfo(String info, String transaction_id, String out_trade_no) {
        Log log = new Log();
        log.setSign(Const.PayInfo.WX_PAY_TYPE);
        log.setIndex01("微信支付金额:" + info);
        log.setIndex02(new Date());
        log.setIndex03(Const.PayInfo.WX_PAY_TRANSACTION_NO + transaction_id);
        log.setIndex04(Const.PayInfo.WX_PAY_ORDER_NO + out_trade_no);
        log.setIndex05("0");
        log.setIndex06("0");
        log.setIndex07("0");
        log.setIndex08("0");
        log.setIndex09("0");
        return log;
    }

    /**
     * 读取参数
     *
     * @param request
     * @return
     */
    private String getInputStream(HttpServletRequest request) {
        StringBuffer stringBuffer = new StringBuffer();
        BufferedReader bufferedReader = null;
        String template;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            while ((template = bufferedReader.readLine()) != null) {
                stringBuffer.append(template);
            }
            return stringBuffer.toString();
        } catch (IOException e) {
            log.info("IO流读取异常", e);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    log.info("IO关闭异常", e);
                }
            }
        }
        return null;
    }

    // -----------------新支付 --------------


    /**
     * 微信公众号支付
     *
     * @param openid
     * @return
     */

    @Override
    public ServerResponse WxPay_public(String openid, String body, String total_fee, String out_trade_no, String attach) {
        if (StringUtils.isBlank(openid)) {
            return ServerResponse.createByErrorMessage("openid不能为空");
        }
        if (StringUtils.isBlank(body) || StringUtils.isBlank(attach)) {
            return ServerResponse.createByErrorMessage("參數不合法");
        }
        if (total_fee == null) {
            return ServerResponse.createByErrorMessage("价格参数不为空");
        }
        //扫码支付
        SortedMap map = WxPaymentUtil.WxPay_public(openid, body, total_fee, out_trade_no, attach);
        return ServerResponse.createBySuccess(map);
    }

    /**
     * 微信小程序支付
     *
     * @param openid
     * @return
     */

    @Override
    public ServerResponse WxPay_miniProgram(String openid, String body, String total_fee, String out_trade_no, String attach) {

        if (StringUtils.isBlank(openid)) {
            return ServerResponse.createByErrorMessage("code不能为空");
        }
        if (StringUtils.isBlank(body) || StringUtils.isBlank(attach)) {
            return ServerResponse.createByErrorMessage("参数不合法");
        }
        if (total_fee == null) {
            return ServerResponse.createByErrorMessage("价格参数不为空");
        }

        SortedMap map = WxPaymentUtil.WxPay_miniProgram(openid, body, total_fee, out_trade_no, attach);
        log.info("【微信小程序支付】返回参数:", map);
        return ServerResponse.createBySuccess("支付成功", map);
    }


    /**
     * 微信支付-回调接口
     *
     * @param request
     * @return
     */
    @Override
    public void WxPay_callback(HttpServletRequest request, HttpServletResponse response) {
        //读取参数
        String template = this.getInputStream(request);
        if (StringUtils.isBlank(template)) {
            log.error("【微信支付回调】获取请求参数错误！");
        }

        //解析XML并转换成Map
        Map<String, String> map = new HashMap<String, String>();
        try {
            map = PayUtil.doXMLParse(template);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //取值
        String totalPrice = (String) map.get("total_fee");
        String orderNo = (String) map.get("out_trade_no");

        //需要返回给微信回调的参数
        String resXml = "";
        //判断是否支付成功
        if ("SUCCESS".equals((String) map.get("result_code"))) {

            log.info("************* 支付成功(微信支付异步通知) - 时间: {} *************", DateTimeUtil.dateToStr(new Date()));
            log.info("* 微信订单号: {}", orderNo);
            log.info("* 实际支付金额: {}", totalPrice);
            log.info("* 交易状态: {}", Const.AlipayCallback.RESPONSE_SUCCESS);
            log.info("*****************************************************************************");

            // 修改订单状态
            iOrderService.updateByOrderNo(orderNo);
            // 异步发送邮件
            String sendMsg = "微信回调:" + totalPrice + "元,订单号：" + orderNo + ",<微信支付平台>";
            asyncTask.sendAdminEmail(sendMsg);

            resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                    + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        } else {
            log.error("【微信支付回调错误】错误信息:", map.get("err_code"));
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        //业务结束,发送结果
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes("UTF-8"));
            out.flush();
            out.close();
        } catch (IOException e) {
            log.error("IO流响应异常", e);
        }
    }

    @Override
    public ServerResponse queryOrderPayStatus(String wechatId, String orderNo) {

        Order order = orderMapper.findOrderByOrderNo(orderNo);
        if (order == null) {
            return ServerResponse.createByErrorMessage("用户没有该订单");
        }
        //判断它的支付状态
        if (order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()) {
            return ServerResponse.createBySuccess();
        }
        return ServerResponse.createByError();
    }

}
